package widget;

import android.content.Context;
import android.content.res.TypedArray;
import android.database.DataSetObserver;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ListAdapter;

import net.ck.hzq.R;

import java.util.ArrayList;
import java.util.List;


/**
 * 流式布局
 * 每项长度根据内容展示
 * 并自动换行，还可以设置左右对其或者居中对齐
 * 使用方式为addView
 * Created by zhangdong on 2017/8/3.
 */
public class FlowLayout extends ViewGroup implements View.OnClickListener {
    public static final int LEFT = 0;
    public static final int CENTER = 1;
    public static final int RIGHT = 2;
    private static final int VIEW_MARGIN = 2;
    private int mLeftMargin = VIEW_MARGIN;
    private int mRightMargin = VIEW_MARGIN;
    private int mTopMargin = VIEW_MARGIN;
    private int mBottomMargin = VIEW_MARGIN;
    //是否分散对齐
    private boolean mIsDistributed;
    private boolean mLastLineFill;
    //是否一行展示（超过一行不展示）
    private boolean mSingleLine = false;
    //对齐方式（左中右，默认居左）,只有当取消分散对齐时有效,即isDistributed 为false时有效
    private int mAlignmentType;
    //所有子view的集合
    private List<List<View>> mAllViews = new ArrayList<>();
    private List<View> mLineViews = new ArrayList<>();
    //每一行的高度集合
    private List<Integer> mLineHeight = new ArrayList<>();
    private List<Integer> mLineWidth = new ArrayList<>();
    private OnItemClickListener mItemClickListener;
    private ListAdapter mAdapter;

    private DataSetObserver mDataSetObserver = new DataSetObserver() {
        @Override
        public void onChanged() {
            super.onChanged();
            bindView();
        }

        @Override
        public void onInvalidated() {
            super.onInvalidated();
            bindView();
        }
    };

    public FlowLayout(Context context) {
        super(context);
    }

    public FlowLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.FlowLayout);
        mAlignmentType = a.getInt(R.styleable.FlowLayout_alignmentType, LEFT);
        mIsDistributed = a.getBoolean(R.styleable.FlowLayout_distributed, true);
        mLastLineFill = a.getBoolean(R.styleable.FlowLayout_lastLineFill, true);
        a.recycle();
    }

    public FlowLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    /**
     * set item view margin
     *
     * @param widthMargin  leftMargin and rightMargin
     * @param heightMargin topMargin and bottomMargin
     */
    public void setViewMargin(int widthMargin, int heightMargin) {
        this.mLeftMargin = widthMargin;
        this.mRightMargin = widthMargin;
        this.mTopMargin = heightMargin;
        this.mBottomMargin = heightMargin;
    }

    /**
     * set item view margin
     *
     * @param leftMargin   leftMargin
     * @param rightMargin  rightMargin
     * @param topMargin    topMargin
     * @param bottomMargin bottomMargin
     */
    public void setViewMargin(int leftMargin, int rightMargin, int topMargin, int bottomMargin) {
        this.mLeftMargin = leftMargin;
        this.mRightMargin = rightMargin;
        this.mTopMargin = topMargin;
        this.mBottomMargin = bottomMargin;
    }

    public void setOnItemClickListener(OnItemClickListener listener) {
        mItemClickListener = listener;
    }

    public void setAdapter(ListAdapter adapter) {
        this.removeAllViews();
        if (mAdapter != null) {
            mAdapter.unregisterDataSetObserver(mDataSetObserver);
        }
        mAdapter = adapter;
        if (mAdapter != null) {
            mAdapter.registerDataSetObserver(mDataSetObserver);
        }
        bindView();
    }

    private void bindView() {
        if (mAdapter == null) {
            return;
        }
        /**
         *  updated by Eric Ding 2017/11/24
         *  增加了removeAllViews()方法，防止每次调用Adapter的notifyDataSetChanged()
         *  方法时出现重复添加item的情况
         **/
        removeAllViews();
        for (int position = 0; position < mAdapter.getCount(); position++) {
            this.addView(mAdapter.getView(position, null, null));
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int modeWidth = MeasureSpec.getMode(widthMeasureSpec);
        int sizeWidth = MeasureSpec.getSize(widthMeasureSpec);
        int modeHeight = MeasureSpec.getMode(heightMeasureSpec);
        int sizeHeight = MeasureSpec.getSize(heightMeasureSpec);

        // wrap_content 处理
        int width = 0, height = 0;
        int lineWidth = 0, lineHeight = 0;

        int childCount = getChildCount();
        for (int i = 0; i < childCount; i++) {
            View child = getChildAt(i);
            measureChild(child, widthMeasureSpec, heightMeasureSpec);

            child.setId(i);
            child.setOnClickListener(this);

            int childWidth;
            int childHeight;

            if (child.getLayoutParams() instanceof MarginLayoutParams) {
                MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
                childWidth = child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin;
                childHeight = child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin;
            } else {
                childWidth = child.getMeasuredWidth() + mLeftMargin + mRightMargin;
                childHeight = child.getMeasuredHeight() + mTopMargin + mBottomMargin;
            }

            // 支持padding
            if (lineWidth + childWidth > sizeWidth - getPaddingLeft() - getPaddingRight() && !mSingleLine) {
                //超过一行展示
                width = Math.max(lineWidth, width);
                height += lineHeight;

                lineWidth = childWidth;
                lineHeight = childHeight;
            } else {
                lineWidth += childWidth;
                lineHeight = Math.max(lineHeight, childHeight);
            }

            if (i == childCount - 1) {
                width = Math.max(lineWidth, childWidth);
                height += lineHeight;
            }
        }

        setMeasuredDimension(
                modeWidth == MeasureSpec.EXACTLY ? sizeWidth : width + getPaddingLeft() + getPaddingRight(),
                modeHeight == MeasureSpec.EXACTLY ? sizeHeight : height + getPaddingTop() + getPaddingBottom()
        );
    }


    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        mAllViews.clear();
        mLineHeight.clear();
        mLineWidth.clear();

        int lineWidth = 0, lineHeight = 0;
        if (mLineViews == null) {
            mLineViews = new ArrayList<>();
        }
        mLineViews.clear();

        // 控件本身的宽度
        int width = getWidth();

        // 遍历所有子控件，填充好 mAllViews 和 mLineHeight
        int childCount = getChildCount();
        for (int i = 0; i < childCount; i++) {
            View child = getChildAt(i);

            int childWidth;
            int childHeight;
            if (child.getLayoutParams() instanceof MarginLayoutParams) {
                MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
                childWidth = child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin;
                childHeight = child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin;
            } else {
                childWidth = child.getMeasuredWidth() + mLeftMargin + mRightMargin;
                childHeight = child.getMeasuredHeight() + mTopMargin + mBottomMargin;
            }

            if (lineWidth + childWidth > width - getPaddingLeft() - getPaddingRight()) {
                if (mSingleLine) {
                    break; //超过一行则跳出循环不再添加view
                }
                //超过一行展示
                mAllViews.add(mLineViews);
                mLineHeight.add(lineHeight);
                mLineWidth.add(lineWidth);

                lineWidth = childWidth;
                lineHeight = childHeight;
                mLineViews = new ArrayList<>();
            } else {
                lineWidth += childWidth;
                lineHeight = Math.max(lineHeight, childHeight);
            }

            mLineViews.add(child);
        }
        mAllViews.add(mLineViews);
        mLineHeight.add(lineHeight);
        mLineWidth.add(lineWidth);

        // 初始左上位置
        int left;
        int top = getPaddingTop();

        for (int i = 0, allSize = mAllViews.size(); i < allSize; i++) {
            mLineViews = mAllViews.get(i);
            lineHeight = mLineHeight.get(i);
            lineWidth = mLineWidth.get(i);

            int availableLineWidth = 0;
            left = getPaddingLeft(); // 左对齐
            if (mIsDistributed) {
                availableLineWidth = width - lineWidth - getPaddingLeft() - getPaddingRight();
            } else if (mAlignmentType == RIGHT) {
                left = width - lineWidth - getPaddingRight(); // 右对齐
            } else if (mAlignmentType == CENTER) {
                left = (width - lineWidth) / 2;  // 居中
            }

            for (int j = 0, lineSize = mLineViews.size(); j < lineSize; j++) {
                View child = mLineViews.get(j);
                if (child.getVisibility() == View.GONE) {
                    continue;
                }

                if (mIsDistributed && !(i == mAllViews.size() - 1 && !mLastLineFill)) {
                    child.setPadding(child.getPaddingLeft() + availableLineWidth / mLineViews.size() / 2,
                            child.getPaddingTop(),
                            child.getPaddingRight() + availableLineWidth / mLineViews.size() / 2,
                            child.getPaddingBottom());
                }

                int lc;
                int tc;
                MarginLayoutParams lp = null;
                if (child.getLayoutParams() instanceof MarginLayoutParams) {
                    lp = (MarginLayoutParams) child.getLayoutParams();
                    lc = left + lp.leftMargin;
                    tc = top + lp.topMargin;
                } else {
                    lc = left + mLeftMargin;
                    tc = top + mTopMargin;
                }
                int rc;
                if (mIsDistributed) {
                    rc = lc + child.getMeasuredWidth() + availableLineWidth / mLineViews.size();

                    if (i == mAllViews.size() - 1 && !mLastLineFill) {
                        rc = lc + child.getMeasuredWidth();
                    }

                } else {
                    rc = lc + child.getMeasuredWidth();
                }
                int bc = tc + child.getMeasuredHeight();

                child.layout(lc, tc, rc, bc);

                if (mIsDistributed) {
                    if (i == mAllViews.size() - 1 && !mLastLineFill) {
                        if (lp == null) {
                            left += mLeftMargin + child.getMeasuredWidth() + mRightMargin;
                        } else {
                            left += lp.leftMargin + child.getMeasuredWidth() + lp.rightMargin;
                        }
                    } else {
                        if (lp == null) {
                            left += mLeftMargin + child.getMeasuredWidth() + mRightMargin + availableLineWidth / mLineViews.size();
                        } else {
                            left += lp.leftMargin + child.getMeasuredWidth() + lp.rightMargin + availableLineWidth / mLineViews.size();
                        }
                    }
                } else {
                    if (lp == null) {
                        left += mLeftMargin + child.getMeasuredWidth() + mRightMargin;
                    } else {
                        left += lp.leftMargin + child.getMeasuredWidth() + lp.rightMargin;
                    }
                }
            }
            top += lineHeight;
        }
    }

    /**
     * 设置对齐方式，只有当不是分散对齐时有效
     * <br>如果需要强制设置非分散对齐，调用 setUnDistributedAndAlignmentType()
     *
     * @param alignmentType 对其方式
     */
    public void setAlignmentType(int alignmentType) {
        if (mIsDistributed || this.mAlignmentType == alignmentType) {
            return;
        }
        this.mAlignmentType = alignmentType;
        requestLayout();
    }

    /**
     * 设置是否分散对齐
     */
    public void setDistributedAndLastLineFill() {
        this.mIsDistributed = true;
        mAlignmentType = LEFT;
        mLastLineFill = true;
        requestLayout();
    }

    /**
     * 设置分散对齐且最后行不填充
     */
    public void setDistributedAndLastLineNotFill() {
        this.mIsDistributed = true;
        mAlignmentType = LEFT;
        mLastLineFill = false;
        requestLayout();
    }

    /**
     * 强制设置非分散对齐，且按照传入的对齐方式
     *
     * @param alignmentType 对其方式
     */
    public void setUnDistributedAndAlignmentType(int alignmentType) {
        mIsDistributed = false;
        this.mAlignmentType = alignmentType;
        requestLayout();
    }

    public boolean isSingleLine() {
        return mSingleLine;
    }

    public void setSingleLine(boolean mSingleLine) {
        this.mSingleLine = mSingleLine;
    }

    @Override
    public LayoutParams generateLayoutParams(AttributeSet attrs) {
        return new MarginLayoutParams(getContext(), attrs);
    }

    @Override
    public void onClick(View view) {
        if (mItemClickListener != null) {
            int position = view.getId();
            mItemClickListener.onItemClick(this, view, position);
        }
    }

    public interface OnItemClickListener {
        void onItemClick(View viewGroup, View view, int position);
    }
}
